学习多线程大家都对它的锁感到郁闷,一般它的锁对象可以有Object,当前类对象this,以及修饰static方法时的类class文件。
比如对于同步代码块:
while (true) {
synchronized (this) {
if (ticket > 0) {
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "还有"
+ (ticket--) + "张票");
} else
break;
}
对于函数中的同步锁:
public synchronized void show(){
while (true) {
if (ticket > 0) {
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "还有"
+ (ticket--) + "张票");
}
}
}
以及static函数中的同步锁:
public synchronized static void show2(){
//省略代码
}
他们3者之间的锁对象不同,对于代码块来说,它的锁是任意的Object对象,如果我们使用了代码块和函数同步,那么我们的锁对象要换位this,这样才能保证线程的安全性,而如果我们使用static函数和代码块同步锁,那么锁对象要使用static函数所在的类的class代码块,如ThreadDemo1.class。
对于两个或两个以上的线程访问同一个资源时,要注意线程的安全问题,如:Input线程向Res类中写数据,Output读数据。
资源对象:
package lh.zjzk;
/**
* 此资源类似与,工厂流水线上的产品,一进,一出
* @author Administrator
*
*/
public class Res {
public String name;
public String sex;
public boolean flag = false;//是否对调用该对象的线程进行锁定以及唤醒
}
加工线程:
package lh.zjzk;
public class Input implements Runnable {
private Res res;
public Input(Res res) {
this.res = res;
}
int x = 0 ;
@Override
public void run() {
while(true){
synchronized(res){//为了保证Input和Output这两个线程使用的是同一个锁,故将res对象传递给同步代码块
try {
if(res.flag)//如果Res已经被赋值,那么将Input线程锁定,等待Output唤醒
res.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
if(x % 2 ==0){
res.name = "张三";
res.sex = "男";
}else{
res.name = "xiaoxiao";
res.sex = "女";
}
x = (x+1) % 2;
res.flag = true;//赋值过后,将唤醒标志改为true
res.notify();//唤醒Output线程输出
}
}
}
}
搬运线程:
package lh.zjzk;
public class Output implements Runnable {
private Res res;
public Output(Res res){
this.res = res;
}
@Override
public void run() {
while(true){
synchronized(res){
try {
if(!res.flag)//如果真,证明资源已经被赋值了,该线程应把它拿走,否则等待
res.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(res.name + "--->"+res.sex);
res.flag = false;//将唤醒标志改为false
res.notify();//唤醒Input对象进行赋值
}
}
}
}
主程序调用加工和搬运线程进行操作:
package lh.zjzk;
public class ThreadMain {
public static void main(String[] args) {
Res res = new Res();
Input in = new Input(res);
Output out = new Output(res);
new Thread(in).start();
new Thread(out).start();
}
}
输出结果: